/*
 * Copyright 2008 Federal Emergency Management Agency
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0 
 *    
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 *  
 */
package gov.fema.hazus.bdc.client.settings;

import gov.fema.hazus.bdc.client.common.entities.AbstractClickListener;
import gov.fema.hazus.bdc.client.common.handlers.LoggingAsyncHandler;
import gov.fema.hazus.bdc.client.common.ui.InCASTTabPanel;
import gov.fema.hazus.bdc.client.common.ui.Message;
import gov.fema.hazus.bdc.client.controller.Controller;
import gov.fema.hazus.bdc.client.login.Login;
import gov.fema.hazus.bdc.client.services.UserServiceProxy;
import gov.fema.hazus.bdc.shared.entity.Building;
import gov.fema.hazus.bdc.shared.entity.User;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

public class UserEditor extends Composite {
    
	private User user;
	
    /**
     * Set up instance for Login
     */
    private static UserEditor singleton;
    public static UserEditor get()
    {
        if( singleton == null )
        {
            singleton = new UserEditor();
        }
        return singleton;
    }
    
    
    class Updater extends LoggingAsyncHandler
    {

        public void handleFailure(Throwable caught) {
            GWT.log("Updater: Send message to UI:" + caught, null);
            Message.get().show(caught.getMessage());
        }

        public void handleSuccess(Object result) {
            
            user = (User) result;
            
            GWT.log("Updating UI widgets with updated user:" + user, null);
            
            updateWidgets(user);
            
            //TODO: put into constants
            Message.get().show("User was saved");
        }

    }
    
    class CancelHandler extends LoggingAsyncHandler
    {

        public void handleFailure(Throwable caught) {
            GWT.log("Updater: Send message to UI:" + caught, null);
            Message.get().show(caught.getMessage());
        }

        public void handleSuccess(Object result) {
            
            // switch to the building list, updated
            // LeftNavigation.get().showBuildingList();
            //TODO: switch to user list in settings
        	
        }

    }    

    public Updater updater = new Updater();
    public CancelHandler cancelHandler = new CancelHandler();
    
    class CancelButtonClickListener extends AbstractClickListener
    {

        @Override
        public void handleClick(Widget sender) {
            
            Message.get().hide();
            /*
            if( user.getId() != null )
            {
                // release the building via the API
            	// BuildingServiceProxy.get().releaseBuilding(building, cancelHandler);
            	//TODO: see if User needs to be released, I don't think so.
            	// because there is only 1 admin who can edit users.
            }
            else
            {
                // building was never saved, so just go back to list view
                Controller.get().mainShowBuildingList();
                //TODO: show user list
            }
            */
            Controller.get().mainShowUserList();

        }
        
    }        
    class SaveButtonClickListener extends AbstractClickListener
    {

        @Override
        public void handleClick(Widget sender) {
            // clear messages
            Message.get().hide();
            GWT.log("SaveButtonClickListener="+sender, null);
            GWT.log("current user="+user, null);
            
            // update edited user from form
            user.setUsername(username.getText());
            user.setPassword(password.getText());
            user.setAdmin(admin.getValue());
            GWT.log("updated user="+user, null);
            
            UserServiceProxy.get().saveUser(user, updater);
        }
        
    }    
    
    class UserDetailUpdater extends LoggingAsyncHandler
    {

        public void handleFailure(Throwable caught) {
            GWT.log("UserDetailUpdater: Send message to UI:" + caught, null);
            Message.get().show(caught.getMessage());
        }

        public void handleSuccess(Object result) {
            
        	/* TODO: investigate if we need this for saving users at all
        	 * 
            // set the color back if we were on a search previously
            
            UIController.get().setSearchBorder(false);
            LeftNavigation.get().highlightLeftNav(constants.leftnavListBuildings());
            Search.get().clearQuery();
            
            building = (Building) result;
            
            GWT.log("Updating building detail:" + building, null);
            
            // run the building list through the formatter
            updateWidgets(building);
            
            // clear the message
            Message.get().hide();
            
            // make this visible
            ////showBuildingDetail();
            BuildingList.get().setVisible(false);
            
            // hide the building list
            //InCAST.get().hideBuildingList();
            //InCAST.get().highlightLeftNav(constants.leftnavListBuildings());
             * 
             */
        }

    }    
    
    public void setBuilding(Building building) {
        this.building = building;
    }

    // entities
    public Building building;
    
    // widgets
    //private GeneralWidget generalWidget;
    //private EarthquakeWidget earthquakeWidget;
    //private FloodWidget floodWidget;
    //private WindWidget windWidget;
    //private NotesWidget notesWidget;
    
    // handlers
    UserEditorHandler userEditorHandler = new UserEditorHandler();


    private VerticalPanel panel = new VerticalPanel();
    //private Constants constants;
    private DockPanel docker;
    private InCASTTabPanel tabPanel;
    private VerticalPanel buttonsNameDisplay;
    private Label prominentUserName;
    private HorizontalPanel northButtonBar;
    private HorizontalPanel southButtonBar;
    private UserDetailUpdater userDetailUpdater;
    private HorizontalPanel panelTitle;
    private Button saveButton = new Button();
    private Button cancelButton = new Button();
    private Label viewMap;
	private HTML userLocked;

	private SettingsConstants constants;

	private TextBox username;

	private PasswordTextBox password;

	private FlexTable userEditTable;
	
	private CheckBox admin;

	private HTML backToList;
    
    
    public UserEditor()
    {
        singleton = this;

        this.user = new User();
        
        constants = (SettingsConstants)GWT.create(SettingsConstants.class);
        docker  = new DockPanel();
        tabPanel = new InCASTTabPanel();
        buttonsNameDisplay = new VerticalPanel();
        
        // display the username name prominently
        String userName = "";
        if (user != null )
        {
            userName = user.getUsername();
        }
        prominentUserName = new Label(userName);
        prominentUserName.setStyleName("building-name");

        // north button bar
        northButtonBar = new HorizontalPanel();
        northButtonBar.setStyleName("north-button-bar");
        northButtonBar.add(prominentUserName);
    
        // south button bar
        southButtonBar = new HorizontalPanel();
        
        // save button
        saveButton = new Button();
        saveButton.setStyleName("incast-command-button");
        saveButton.setText(constants.saveButton());
        saveButton.addClickListener(new SaveButtonClickListener());

        // cancel button
        cancelButton = new Button();
        cancelButton.setStyleName("incast-command-button");
        cancelButton.setText("Cancel");
        cancelButton.addClickListener(new CancelButtonClickListener());
        
        // back to list link
        backToList = new HTML("Back to list");
        backToList.setStyleName("emcode-text-link");
        backToList.addClickListener(new CancelButtonClickListener());
        backToList.setWidth("100px");
        /*
         * Put save, cancel in a fixed width 
         * flex table, then in the horizontal panel
         * with a left alignment
         */
        FlexTable bottomCommands = new FlexTable();
        bottomCommands.setWidth("");
        
        bottomCommands.setWidget(0, 0, saveButton);
        bottomCommands.getColumnFormatter().setWidth(0, "10");
        
        bottomCommands.setWidget(0, 1, cancelButton);
        bottomCommands.getColumnFormatter().setWidth(1, "10");
        
        bottomCommands.setWidget(0, 2, backToList);
        //bottomCommands.getColumnFormatter().setWidth(2, "30px");
        
        
        southButtonBar.add(bottomCommands);
        southButtonBar.setStyleName("south-button-bar");
        
        buttonsNameDisplay.add(prominentUserName);
        buttonsNameDisplay.setStyleName("north-button-bar");
        buttonsNameDisplay.add(northButtonBar);
        
        docker.add(buttonsNameDisplay, DockPanel.NORTH);
        docker.add(southButtonBar, DockPanel.SOUTH);
        
        // add the password label field to the center
        userEditTable = new FlexTable();
        
        Label userNameLabel = new Label("Username");
        Label passwordLabel = new Label("Password");
        Label adminLabel = new Label("Administrator");
        
        username = new TextBox();
        username.setText(user.getUsername());
        
        password = new PasswordTextBox();
        password.setText(user.getPassword());
        
        admin = new CheckBox();
        admin.setValue(false);// default is unchecked
        
        userEditTable.setWidget(0, 0, userNameLabel);
        userEditTable.setWidget(0, 1, username);
        userEditTable.setWidget(1, 0, passwordLabel);
        userEditTable.setWidget(1, 1, password);
        userEditTable.setWidget(2, 0, adminLabel);
        userEditTable.setWidget(2, 1, admin);
        
        docker.add(userEditTable, DockPanel.CENTER);
        docker.setCellVerticalAlignment(userEditTable, HasVerticalAlignment.ALIGN_TOP);
        
        docker.setStyleName("docker-building-detail");
        docker.setHeight("100%");
        
        // updaters
        userDetailUpdater = new UserDetailUpdater();
        
        initWidget(docker);
        
    }
    
    
    public void getUser(User user)
    {
        UserServiceProxy.get().getUser(user, userEditorHandler);
    }
    
    private class UserEditorHandler extends LoggingAsyncHandler
    {

        private User user;

		@Override
        public void handleFailure(Throwable caught) {
            GWT.log("failure=" + caught.getMessage(), null);
            Message.get().show(caught.getMessage());
        }

        @Override
        public void handleSuccess(Object result) {
            
            
            GWT.log("fetched user for editing="+result, null);
            
            Message.get().hide();
            
            //MainUI.get().setSearchBorder(false);
            //LeftNavigation.get().highlightLeftNav(constants.leftnavListBuildings());
            //Search.get().clearQuery();
            
            User user = (User) result;
            updateWidgets(user);
            
            /*
             * The fetch could have been successful, but we
             * still might have a in Building.READ_ONLY mode
             * because it is being edited by another user.
             */
//            if( building.getMode().equalsIgnoreCase(Building.READ_ONLY))
//            {
//                Message.get().show("This building is read only");
//            }
            
            //setBuilding(building);
            //updateWidgets(building);
            //Controller.get().mainShowBuildingEditor();
            //TODO: fire to controller to show user editor
            Controller.get().mainShowUserEditor();
        }
        
    }

    
    public void updateBuilding(Building building) {
        //updateWidgets(building);
    }
    
    public void updateWidgets(User user)
    {
        
        this.user = user;
        
        // can't edit an admin username or password
        // unless we are 'superadmin' user
        if( user.isAdmin() )
        {
        	username.setEnabled(false);
        	password.setEnabled(false);
        	admin.setEnabled(false);
        } else {
        	username.setEnabled(true);
        	password.setEnabled(true);
        	admin.setEnabled(false); // only superadmin can create/edit other admins
        }
        
        User currentUser = Login.get().getLoginUser();
        if( currentUser.getUsername().equalsIgnoreCase("superadmin"))
        {
        	username.setEnabled(true);
        	password.setEnabled(true);
        	admin.setEnabled(true); // only superadmin can create/edit other admins
        }
        
        GWT.log("logged in user:" + currentUser, null);
        GWT.log("user being edited:" + user, null);
        if( currentUser.getUsername().equalsIgnoreCase("superadmin")
        		&& user.getUsername().equalsIgnoreCase("superadmin"))
        {
        	username.setEnabled(false); // no one can change the superadmin name
        	password.setEnabled(true); // only superadmin can change superadmin password
        	admin.setEnabled(false); // no one can change admin status of superadmin
        }
        
        // all admins can change their own passwords, but not username or admin status
        if( currentUser.getUsername().equalsIgnoreCase(user.getUsername()))
        {
        	username.setEnabled(false);
        	password.setEnabled(true);
        	admin.setEnabled(false);
        }
        
        
        prominentUserName.setText(user.getUsername());
        username.setText(user.getUsername());
        password.setText(user.getPassword());
        // check the box or not if user is admin
        if( user.isAdmin() )
        {
        	admin.setValue(true);
        } else {
        	admin.setValue(false);
        }
        
    }    

    
    public static void actionWrapperEditUser(String id)
    {
    	GWT.log("edit user id=" + id, null);
    	User u = new User();
    	// TODO: EDIT USER TEMP CHANGE u.setId(id);
    	UserEditor.get().getUser(u);
    }    
    
	public static void actionWrapperSetVisible(boolean flag)
	{
		GWT.log("Executing UserEditor.get().actionWrapperSetVisible("+flag+")", null);
		UserEditor.get().setVisible(flag);
	}


	public void addNewUser() {
		User newUser = new User();
		newUser.setAdmin(false);
		newUser.setUsername("New user");
		updateWidgets(newUser);
	}    

}
